]> dgit.raspbian.org Git - gnome-shell.git/commitdiff
extensionPrefs: Use template for preference dialog
authorFlorian Müllner <fmuellner@gnome.org>
Fri, 6 Mar 2020 00:03:45 +0000 (01:03 +0100)
committerFlorian Müllner <florian.muellner@gmail.com>
Mon, 23 Mar 2020 15:39:12 +0000 (15:39 +0000)
The dialog that contains the extension's preference widget has become
fairly complex over time, mostly due to the error handling.

It therefore makes sense to move it to a template, just like we did
for the main application window and extension rows.

https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/1106

js/extensionPrefs/data/css/application.css
js/extensionPrefs/data/org.gnome.Extensions.data.gresource.xml
js/extensionPrefs/data/ui/extension-prefs-dialog.ui [new file with mode: 0644]
js/extensionPrefs/js/main.js
po/POTFILES.in

index 37105d08191dd9e5c7e436f3eab07cbc9a945749..5641c5d2326d8e4f2f364feba7436b6a1aec6936 100644 (file)
@@ -9,3 +9,6 @@
 }
 
 image.warning { color: @warning_color; }
+
+.expander-frame > * { border-top-width: 0; }
+.expander-toolbar { border: 0 solid @borders; border-top-width: 1px; }
index 659c03ffc860a68157a75e82b5382d56a3e91934..de65e08233190af34bcb3ee40bd68149cf3913de 100644 (file)
@@ -5,6 +5,7 @@
 
     <file>dbus-interfaces/org.gnome.Shell.Extensions.xml</file>
 
+    <file>ui/extension-prefs-dialog.ui</file>
     <file>ui/extension-row.ui</file>
     <file>ui/extensions-window.ui</file>
   </gresource>
diff --git a/js/extensionPrefs/data/ui/extension-prefs-dialog.ui b/js/extensionPrefs/data/ui/extension-prefs-dialog.ui
new file mode 100644 (file)
index 0000000..fc08eae
--- /dev/null
@@ -0,0 +1,197 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.22.1 -->
+<interface>
+  <requires lib="gtk+" version="3.20"/>
+  <template class="ExtensionPrefsDialog" parent="GtkWindow">
+    <property name="default_width">600</property>
+    <property name="default_height">400</property>
+    <child type="titlebar">
+      <object class="GtkHeaderBar" id="headerBar">
+        <property name="visible">True</property>
+        <property name="show_close_button">True</property>
+      </object>
+    </child>
+    <child>
+      <object class="GtkStack" id="stack">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <child>
+          <object class="GtkScrolledWindow">
+            <property name="visible">True</property>
+            <property name="hscrollbar_policy">never</property>
+            <property name="propagate_natural_height">True</property>
+            <child>
+              <object class="GtkViewport">
+                <property name="visible">True</property>
+                <child>
+                  <object class="GtkBox">
+                    <property name="visible">True</property>
+                    <property name="orientation">vertical</property>
+                    <property name="margin">100</property>
+                    <property name="margin_bottom">60</property>
+                    <property name="spacing">12</property>
+                    <child>
+                      <object class="GtkLabel">
+                        <property name="visible">True</property>
+                        <property name="label" translatable="yes">Something’s gone wrong</property>
+                        <attributes>
+                          <attribute name="scale" value="1.44"/> <!-- x-large -->
+                        </attributes>
+                        <style>
+                          <class name="dim-label"/>
+                        </style>
+                      </object>
+                    </child>
+                    <child>
+                      <object class="GtkLabel">
+                        <property name="visible">True</property>
+                        <property name="label" translatable="yes">We’re very sorry, but there’s been a problem: the settings for this extension can’t be displayed. We recommend that you report the issue to the extension authors.</property>
+                        <property name="justify">center</property>
+                        <property name="wrap">True</property>
+                        <property name="xalign">0.5</property>
+                        <property name="yalign">0.5</property>
+                      </object>
+                    </child>
+                    <child>
+                      <object class="GtkBox">
+                        <property name="visible">True</property>
+                        <property name="orientation">vertical</property>
+                        <property name="margin_top">12</property>
+                        <child>
+                          <object class="GtkFrame" id="expander">
+                            <property name="visible">True</property>
+                            <property name="hexpand">True</property>
+                            <property name="shadow_type">in</property>
+                            <child>
+                              <object class="GtkEventBox">
+                                <property name="visible">True</property>
+                                <child>
+                                  <object class="GtkBox">
+                                    <property name="visible">True</property>
+                                    <property name="margin">12</property>
+                                    <property name="spacing">6</property>
+                                    <child>
+                                      <object class="GtkImage" id="expanderArrow">
+                                        <property name="visible">True</property>
+                                        <property name="icon_name">pan-end-symbolic</property>
+                                      </object>
+                                    </child>
+                                    <child>
+                                      <object class="GtkLabel">
+                                        <property name="visible">True</property>
+                                        <property name="label" translatable="yes">Technical Details</property>
+                                      </object>
+                                    </child>
+                                  </object>
+                                </child>
+                              </object>
+                            </child>
+                          </object>
+                        </child>
+                        <child>
+                          <object class="GtkRevealer" id="revealer">
+                            <property name="visible">True</property>
+                            <child>
+                              <object class="GtkFrame">
+                                <property name="visible">True</property>
+                                <property name="shadow_type">in</property>
+                                <style>
+                                  <class name="expander-frame"/>
+                                </style>
+                                <child>
+                                  <object class="GtkBox">
+                                    <property name="visible">True</property>
+                                    <property name="orientation">vertical</property>
+                                    <child>
+                                      <object class="GtkTextView" id="errorView">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">True</property>
+                                        <property name="monospace">True</property>
+                                        <property name="editable">False</property>
+                                        <property name="wrap_mode">word</property>
+                                        <property name="left_margin">12</property>
+                                        <property name="right_margin">12</property>
+                                        <property name="top_margin">12</property>
+                                        <property name="bottom_margin">12</property>
+                                      </object>
+                                    </child>
+                                    <child>
+                                      <object class="GtkToolbar">
+                                        <property name="visible">True</property>
+                                        <style>
+                                          <class name="expander-toolbar"/>
+                                        </style>
+                                        <child>
+                                          <object class="GtkToolItem">
+                                            <property name="visible">True</property>
+                                            <child>
+                                              <object class="GtkButton">
+                                                <property name="visible">True</property>
+                                                <property name="can_focus">True</property>
+                                                <property name="receives_default">True</property>
+                                                <property name="action_name">win.copy-error</property>
+                                                <style>
+                                                  <class name="flat"/>
+                                                  <class name="image-button"/>
+                                                </style>
+                                                <child>
+                                                  <object class="GtkImage">
+                                                    <property name="visible">True</property>
+                                                    <property name="icon_name">edit-copy-symbolic</property>
+                                                  </object>
+                                                </child>
+                                              </object>
+                                            </child>
+                                          </object>
+                                        </child>
+                                        <child>
+                                          <object class="GtkSeparatorToolItem">
+                                            <property name="visible">True</property>
+                                            <property name="draw">False</property>
+                                          </object>
+                                          <packing>
+                                            <property name="expand">True</property>
+                                          </packing>
+                                        </child>
+                                        <child>
+                                          <object class="GtkToolItem">
+                                            <property name="visible">True</property>
+                                            <child>
+                                              <object class="GtkButton" id="homeButton">
+                                                <property name="visible"
+                                                          bind-source="homeButton"
+                                                          bind-property="sensitive"
+                                                          bind-flags="sync-create"/>
+                                                <property name="label" translatable="yes">Homepage</property>
+                                                <property name="tooltip_text" translatable="yes">Visit extension homepage</property>
+                                                <property name="can_focus">True</property>
+                                                <property name="receives_default">True</property>
+                                                <property name="no_show_all">True</property>
+                                                <property name="action_name">win.show-url</property>
+                                                <style>
+                                                  <class name="flat"/>
+                                                </style>
+                                              </object>
+                                            </child>
+                                          </object>
+                                        </child>
+                                      </object>
+                                    </child>
+                                  </object>
+                                </child>
+                              </object>
+                            </child>
+                          </object>
+                        </child>
+                      </object>
+                    </child>
+                  </object>
+                </child>
+              </object>
+            </child>
+          </object>
+        </child>
+      </object>
+    </child>
+  </template>
+</interface>
index d1da73a025bb2fd72a79e5c01e9772a5b47633ee..fd8c00959328f3aca187be80f996127cfd26d1c8 100644 (file)
@@ -191,31 +191,10 @@ var ExtensionsWindow = GObject.registerClass({
         if (!row || !row.hasPrefs)
             return false;
 
-        let widget;
-
-        try {
-            widget = row.prefsModule.buildPrefsWidget();
-        } catch (e) {
-            widget = this._buildErrorUI(row, e);
-        }
-
-        this._prefsDialog = new Gtk.Window({
-            application: this.application,
-            default_width: 600,
-            default_height: 400,
-            modal: this.visible,
-            type_hint: Gdk.WindowTypeHint.DIALOG,
-            window_position: Gtk.WindowPosition.CENTER,
-        });
-
-        this._prefsDialog.set_titlebar(new Gtk.HeaderBar({
-            show_close_button: true,
-            title: row.name,
-            visible: true,
-        }));
+        this._prefsDialog = new ExtensionPrefsDialog(row);
 
         if (this.visible)
-            this._prefsDialog.transient_for = this;
+            this._prefsDialog.set({ transient_for: this, modal: true });
 
         this._prefsDialog.connect('destroy', () => {
             this._prefsDialog = null;
@@ -224,7 +203,6 @@ var ExtensionsWindow = GObject.registerClass({
                 this.destroy();
         });
 
-        this._prefsDialog.add(widget);
         this._prefsDialog.show();
 
         return true;
@@ -266,121 +244,6 @@ var ExtensionsWindow = GObject.registerClass({
             });
     }
 
-    _buildErrorUI(row, exc) {
-        let scroll = new Gtk.ScrolledWindow({
-            hscrollbar_policy: Gtk.PolicyType.NEVER,
-            propagate_natural_height: true,
-        });
-
-        let box = new Gtk.Box({
-            orientation: Gtk.Orientation.VERTICAL,
-            spacing: 12,
-            margin: 100,
-            margin_bottom: 60,
-        });
-        scroll.add(box);
-
-        let label = new Gtk.Label({
-            label: '<span size="x-large">%s</span>'.format(_("Something’s gone wrong")),
-            use_markup: true,
-        });
-        label.get_style_context().add_class(Gtk.STYLE_CLASS_DIM_LABEL);
-        box.add(label);
-
-        label = new Gtk.Label({
-            label: _("We’re very sorry, but there’s been a problem: the settings for this extension can’t be displayed. We recommend that you report the issue to the extension authors."),
-            justify: Gtk.Justification.CENTER,
-            wrap: true,
-        });
-        box.add(label);
-
-        let expander = new Expander({
-            label: _("Technical Details"),
-            margin_top: 12,
-        });
-        box.add(expander);
-
-        let errortext = '%s\n\nStack trace:\n'.format(exc);
-        // Indent stack trace.
-        errortext +=
-            exc.stack.split('\n').map(line => '  %s'.format(line)).join('\n');
-
-        let buffer = new Gtk.TextBuffer({ text: errortext });
-        let textview = new Gtk.TextView({
-            buffer,
-            wrap_mode: Gtk.WrapMode.WORD,
-            monospace: true,
-            editable: false,
-            top_margin: 12,
-            bottom_margin: 12,
-            left_margin: 12,
-            right_margin: 12,
-        });
-
-        let toolbar = new Gtk.Toolbar();
-        let provider = new Gtk.CssProvider();
-        provider.load_from_data(`* {
-            border: 0 solid @borders;
-            border-top-width: 1px;
-        }`);
-        toolbar.get_style_context().add_provider(
-            provider,
-            Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION
-        );
-
-        let copyButton = new Gtk.ToolButton({
-            icon_name: 'edit-copy-symbolic',
-            tooltip_text: _("Copy Error"),
-        });
-        toolbar.add(copyButton);
-
-        copyButton.connect('clicked', w => {
-            let clipboard = Gtk.Clipboard.get_default(w.get_display());
-            // markdown for pasting in gitlab issues
-            let lines = [
-                'The settings of extension %s had an error:'.format(row.uuid),
-                '```', // '`' (xgettext throws up on odd number of backticks)
-                exc.toString(),
-                '```', // '`'
-                '',
-                'Stack trace:',
-                '```', // '`'
-                exc.stack.replace(/\n$/, ''), // stack without trailing newline
-                '```', // '`'
-                '',
-            ];
-            clipboard.set_text(lines.join('\n'), -1);
-        });
-
-        let spacing = new Gtk.SeparatorToolItem({ draw: false });
-        toolbar.add(spacing);
-        toolbar.child_set_property(spacing, "expand", true);
-
-        let urlButton = new Gtk.ToolButton({
-            label: _("Homepage"),
-            tooltip_text: _("Visit extension homepage"),
-            no_show_all: true,
-            visible: row.url !== '',
-        });
-        toolbar.add(urlButton);
-
-        urlButton.connect('clicked', w => {
-            let context = w.get_display().get_app_launch_context();
-            Gio.AppInfo.launch_default_for_uri(row.url, context);
-        });
-
-        let expandedBox = new Gtk.Box({
-            orientation: Gtk.Orientation.VERTICAL,
-        });
-        expandedBox.add(textview);
-        expandedBox.add(toolbar);
-
-        expander.add(expandedBox);
-
-        scroll.show_all();
-        return scroll;
-    }
-
     _sortList(row1, row2) {
         return row1.name.localeCompare(row2.name);
     }
@@ -504,105 +367,6 @@ var ExtensionsWindow = GObject.registerClass({
     }
 });
 
-var Expander = GObject.registerClass({
-    Properties: {
-        'label': GObject.ParamSpec.string(
-            'label', 'label', 'label',
-            GObject.ParamFlags.READWRITE,
-            null
-        ),
-    },
-}, class Expander extends Gtk.Box {
-    _init(params = {}) {
-        this._labelText = null;
-
-        super._init(Object.assign(params, {
-            orientation: Gtk.Orientation.VERTICAL,
-            spacing: 0,
-        }));
-
-        this._frame = new Gtk.Frame({
-            shadow_type: Gtk.ShadowType.IN,
-            hexpand: true,
-        });
-
-        let eventBox = new Gtk.EventBox();
-        this._frame.add(eventBox);
-
-        let hbox = new Gtk.Box({
-            spacing: 6,
-            margin: 12,
-        });
-        eventBox.add(hbox);
-
-        this._arrow = new Gtk.Image({
-            icon_name: 'pan-end-symbolic',
-        });
-        hbox.add(this._arrow);
-
-        this._label = new Gtk.Label({ label: this._labelText });
-        hbox.add(this._label);
-
-        this._revealer = new Gtk.Revealer();
-
-        this._childBin = new Gtk.Frame({
-            shadow_type: Gtk.ShadowType.IN,
-        });
-        this._revealer.add(this._childBin);
-
-        // Directly chain up to parent for internal children
-        super.add(this._frame);
-        super.add(this._revealer);
-
-        let provider = new Gtk.CssProvider();
-        provider.load_from_data('* { border-top-width: 0; }');
-        this._childBin.get_style_context().add_provider(
-            provider,
-            Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION
-        );
-
-        this._gesture = new Gtk.GestureMultiPress({
-            widget: this._frame,
-            button: 0,
-            exclusive: true,
-        });
-        this._gesture.connect('released', (gesture, nPress) => {
-            if (nPress == 1)
-                this._revealer.reveal_child = !this._revealer.reveal_child;
-        });
-        this._revealer.connect('notify::reveal-child', () => {
-            if (this._revealer.reveal_child)
-                this._arrow.icon_name = 'pan-down-symbolic';
-            else
-                this._arrow.icon_name = 'pan-end-symbolic';
-        });
-    }
-
-    get label() {
-        return this._labelText;
-    }
-
-    set label(text) {
-        if (this._labelText == text)
-            return;
-
-        if (this._label)
-            this._label.label = text;
-        this._labelText = text;
-        this.notify('label');
-    }
-
-    add(child) {
-        // set expanded child
-        this._childBin.get_children().forEach(c => {
-            this._childBin.remove(c);
-        });
-
-        if (child)
-            this._childBin.add(child);
-    }
-});
-
 var ExtensionRow = GObject.registerClass({
     GTypeName: 'ExtensionRow',
     Template: 'resource:///org/gnome/Extensions/ui/extension-row.ui',
@@ -768,6 +532,105 @@ var ExtensionRow = GObject.registerClass({
     }
 });
 
+var ExtensionPrefsDialog = GObject.registerClass({
+    GTypeName: 'ExtensionPrefsDialog',
+    Template: 'resource:///org/gnome/Extensions/ui/extension-prefs-dialog.ui',
+    InternalChildren: [
+        'headerBar',
+        'stack',
+        'expander',
+        'expanderArrow',
+        'revealer',
+        'errorView',
+    ],
+}, class ExtensionPrefsDialog extends Gtk.Window {
+    _init(extension) {
+        super._init();
+
+        this._uuid = extension.uuid;
+        this._url = extension.url;
+
+        this._headerBar.title = extension.name;
+
+        this._actionGroup = new Gio.SimpleActionGroup();
+        this.insert_action_group('win', this._actionGroup);
+
+        this._initActions();
+
+        this._gesture = new Gtk.GestureMultiPress({
+            widget: this._expander,
+            button: 0,
+            exclusive: true,
+        });
+
+        this._gesture.connect('released', (gesture, nPress) => {
+            if (nPress === 1)
+                this._revealer.reveal_child = !this._revealer.reveal_child;
+        });
+
+        this._revealer.connect('notify::reveal-child', () => {
+            this._expanderArrow.icon_name = this._revealer.reveal_child
+                ? 'pan-down-symbolic'
+                : 'pan-end-symbolic';
+        });
+
+        try {
+            const widget = extension.prefsModule.buildPrefsWidget();
+            this._stack.add(widget);
+            this._stack.visible_child = widget;
+        } catch (e) {
+            this._setError(e);
+        }
+    }
+
+    _setError(exc) {
+        this._errorView.buffer.text = '%s\n\nStack trace:\n'.format(exc);
+        // Indent stack trace.
+        this._errorView.buffer.text +=
+            exc.stack.split('\n').map(line => '  %s'.format(line)).join('\n');
+
+        // markdown for pasting in gitlab issues
+        let lines = [
+            'The settings of extension %s had an error:'.format(this._uuid),
+            '```', // '`' (xgettext throws up on odd number of backticks)
+            exc.toString(),
+            '```', // '`'
+            '',
+            'Stack trace:',
+            '```', // '`'
+            exc.stack.replace(/\n$/, ''), // stack without trailing newline
+            '```', // '`'
+            '',
+        ];
+        this._errorMarkdown = lines.join('\n');
+        this._actionGroup.lookup('copy-error').enabled = true;
+    }
+
+    _initActions() {
+        let action;
+
+        action = new Gio.SimpleAction({
+            name: 'copy-error',
+            enabled: false,
+        });
+        action.connect('activate', () => {
+            const clipboard = Gtk.Clipboard.get_default(this.get_display());
+            clipboard.set_text(this._errorMarkdown, -1);
+        });
+        this._actionGroup.add_action(action);
+
+        action = new Gio.SimpleAction({
+            name: 'show-url',
+            enabled: this._url !== '',
+        });
+        action.connect('activate', () => {
+            Gio.AppInfo.launch_default_for_uri(this._url,
+                this.get_display().get_app_launch_context());
+        });
+        this._actionGroup.add_action(action);
+    }
+});
+
 function initEnvironment() {
     // Monkey-patch in a "global" object that fakes some Shell utilities
     // that ExtensionUtils depends on.
index 3a0c0a151dbf8c01d2633e3522315093d80e65e1..ba8a5b13bd33d5548bc3dfb5b6a422b90fbefbf4 100644 (file)
@@ -7,6 +7,7 @@ data/org.gnome.Shell.PortalHelper.desktop.in.in
 js/extensionPrefs/data/metainfo/org.gnome.Extensions.metainfo.xml.in
 js/extensionPrefs/data/org.gnome.Extensions.desktop.in.in
 js/extensionPrefs/js/main.js
+js/extensionPrefs/data/ui/extension-prefs-dialog.ui
 js/extensionPrefs/data/ui/extension-row.ui
 js/extensionPrefs/data/ui/extensions-window.ui
 js/gdm/authPrompt.js